import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tx_live_plugin/widget/tx_live_push.dart';
import 'package:tx_live_plugin_example/http/http_client.dart';
import 'package:tx_live_plugin_example/http/url_path.dart';
import 'package:tx_live_plugin_example/util/click.dart';
import 'package:tx_live_plugin_example/util/logic_presenter.dart';
import 'package:tx_live_plugin_example/util/toast_utils.dart';
import 'package:tx_live_plugin_example/util/widget_utils.dart';
import 'package:tx_live_plugin_example/widget/life_state.dart';

///推流
class PushPage extends StatefulWidget {
  const PushPage({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _PushPageState();
}

class _PushPageState extends LifeState<PushPage> {
  late PushModel _pushModel;

  @override
  void initState() {
    super.initState();
    _pushModel = PushModel(
        showBottomSheet: _showBottomSheet,
        showDialogBack: _showDialogBack,
        disposePage: _disposePage);
    _pushModel.addListener(() {
      if (mounted) setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          leading: InkWell(
              onTap: ()=> Navigator.pop(context,_pushModel.videoInfo),
              child: const Icon(Icons.arrow_back_ios_rounded, size: 18)),
          actions: _actionsWidget()),
      body: Stack(
        children: [
          Positioned.fill(child: Container(color: Colors.black12)),
          TxLivePush(controller: _pushModel.controller, callback: _pushModel),
          Align(alignment: Alignment.bottomCenter, child: _switchPushBtn()),
          Align(
              alignment: Alignment.topCenter,
              child: Visibility(
                  visible: _pushModel.isLoading,
                  child: const CupertinoActivityIndicator()))
        ],
      ),
    );
  }

  List<Widget> _actionsWidget() {
    if (_pushModel.isPushing) return [];
    var flash =
        _pushModel.isFlash ? Icons.flash_on_rounded : Icons.flash_off_rounded;
    var front = _pushModel.isFrontCamera
        ? Icons.camera_front_rounded
        : Icons.camera_alt;
    return [
      if(!_pushModel.isFrontCamera)_action(flash, onTap: _pushModel.switchFlash),
      _action(front, onTap: _pushModel.switchCamera),
    ];
  }

  Widget _switchPushBtn() {
    return SafeArea(
      child: Padding(
        padding: const EdgeInsets.all(15),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(30),
          child: Click(
            onTap: _pushModel.switchPush,
            child: _pushModel.isPushing
                ? const Icon(Icons.pause_circle_filled,
                color: Colors.redAccent,size: 60)
                : const Icon(Icons.play_circle_fill_rounded,
                color: Colors.redAccent,size: 60),
          ),
        ),
      ),
    );
  }

  Widget _action(IconData data, {Function? onTap}) {
    return Click(
      onTap: onTap,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
        child: Icon(data, size: 18),
      ),
    );
  }

  @override
  void onResumed() {
    _pushModel.controller.onResume();
  }

  @override
  void onPaused() {
    _pushModel.controller.onPause();
  }

  @override
  void dispose() {
    _pushModel.controller.dispose();
    super.dispose();
  }

  void _showBottomSheet(value) {
    var controller = showBottomSheet(
        context: context,
        backgroundColor: Colors.black54,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
        builder: (con) {
          return SafeArea(
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
              child: Text(value ?? '',
                  style: const TextStyle(color: Colors.white)),
            ),
          );
        });
    Future.delayed(const Duration(milliseconds: 800), () => controller.closed);
  }

  _showDialogBack(String msg) async {
    await WidgetUtils.showSingleDialog(context, msg);
  }

  void _disposePage() {
    Navigator.pop(context,_pushModel.videoInfo);
  }
}

///推流管理
class PushModel extends ChangeNotifier with PushCallback {
  final PushController controller = PushController();
  final ValueChanged? showBottomSheet;
  final VoidCallback? disposePage;
  final Function(String msg)? showDialogBack;
  String? _pushUrl;
  String? _streamId;
  bool isPushing = false;
  bool isLoading = false;
  bool isFlash = false;
  bool isFrontCamera = false;
  Timer? _timer;
  Map? videoInfo;

  PushModel({
    this.showBottomSheet,
    this.showDialogBack,
    this.disposePage,
  });

  switchPush() async {
    var pushing = await controller.isPushRecording();
    if (pushing is bool) {
      if (pushing == true) {
        await _stopPush();
      } else {
        await _startPush();
      }
    } else {
      controller.startLivePush();
    }
  }

  _startPush() async {
    if (ToastUtils.emptyToast(LogicPresenter.user?.token, "token为空，请先登录")) {
      return;
    }
    isLoading = true;
    notifyListeners();
    await HttpClient.post(UrlPath.GET_PUSH_URL, params: {
      "ratio": "360p",
      "orgId": LogicPresenter.user?.orgId,
    }, onValue: (res) {
      _pushUrl = res['pushUrl'];
      _streamId = res['streamId'];
      int serverTime = res['serverTime'];
      controller.startLivePush(
          url: _pushUrl, serverTime: serverTime, isBitrateStandard: true);
      isPushing = true;
      return res;
    });
    isLoading = false;
    notifyListeners();
  }

  switchFlash() async {
    await controller.turnOnFlashLight();
    isFlash = await controller.isFlashLightOpen();
    notifyListeners();
  }

  switchCamera() async {
    await controller.switchCamera();
    isFrontCamera = await controller.isFontCamera();
    notifyListeners();
  }

  @override
  dispose() {
    print("----------------push page dispose");
    controller.onDestroy();
    _timer?.cancel();
    super.dispose();
  }

  _stopPush() async {
    isPushing = false;
    _timer?.cancel();
    _requestStopPush();
  }

  _requestStopPush() async {
    if (_streamId == null) return;
    isLoading = true;
    notifyListeners();
    await HttpClient.post(UrlPath.STOP_PUSH_STREAM, params: {
      "streamId": _streamId,
    }, onValue: (res) {
      ToastUtils.showToast("录制成功");
      _streamId = null;
      videoInfo = res;
      disposePage?.call();
      return res;
    }, onMsg: (e) {
      _dialogForDispose(e?.msg ?? '录制异常');
      return false;
    });
    isLoading = false;
    notifyListeners();
  }

  ///弹窗提示后，关闭页面
  _dialogForDispose(value) async {
    await showDialogBack?.call(value);
    disposePage?.call();
  }

  @override
  notifyPushStart() async{
    isLoading = true;
    notifyListeners();
    await HttpClient.post(UrlPath.START_PUSH_STREAM, params: {
      "streamId": _streamId
    }, onValue: (res) {
      return res;
    });
    isLoading = false;
    notifyListeners();
  }

  @override
  stopLivePush({bool? cameraError, bool? needNoticeServer}) async {
    String str;
    if (cameraError == true) {
      str = "相机开启异常，无法录制";
    } else if (needNoticeServer == true) {
      str = "录制结束";
      _requestStopPush();
    } else {
      str = "录制关闭";
    }
    toast(str);
    disposePage?.call();
  }

  @override
  toast(String? message) {
    ToastUtils.showToast(message ?? '');
  }

  @override
  toastErrorInfo(String? method, data) {
    showDialogBack?.call("method $method,data $data");
  }

  @override
  error(String? message) async{
    await showDialogBack?.call(message??'');
    disposePage?.call();
  }

  @override
  toastSnackBar(String? message) {
    showBottomSheet?.call(message);
  }

  @override
  videoProcessListener() {}
}
